package com.distortiongames.level27.generation
{
	import com.distortiongames.level27.generation.random.Chance;
	import com.distortiongames.level27.generation.random.ChanceWithMinimum;
	import com.distortiongames.level27.generation.random.ElementalChance;
	import com.distortiongames.level27.math.SeededRand;
	
	/**
	 * ...
	 * @author Jefferson Wagner
	 */
	public class Generator
	{
		public static var random:SeededRand;
		
		
		private var builders:Vector.<Builder>;
		public var ends:Vector.<Point>;
		public var lastMap:Map;
		public var start:Point;
		private var done:Boolean;
		public var numberOfSteps:int;
		private var lastAge:int;
		public var rooms:Vector.<Room>;
		
		public var lastPhrase:Phrase;
		
		private var width:int, height:int;
		
		public function Generator(phrase:Phrase, width:int = 100, height:int = 100)
		{
			this.lastPhrase = phrase;
			random = new SeededRand(phrase.seed);
			this.width = width;
			this.height = height;
		}
		
		public function generate(beginStepping:Boolean):Map
		{
			numberOfSteps = 0;
			builders = new Vector.<Builder>;
			ends = new Vector.<Point>;
			rooms = new Vector.<Room>;
			lastMap = new Map(width, height);
			var initialParameters:Parameters = new Parameters();
			lastAge = 200 + lastPhrase.properties["size"] * 50;
			initialParameters.setAge(new ChanceWithMinimum(1,1, lastAge));
			initialParameters.setForkChance(new Chance(50, 0));
			var branching:int = lastPhrase.properties["branching"];
			initialParameters.setSpawnBranch(new ChanceWithMinimum(50, 5, 7-branching));
			var corridor:int = lastPhrase.properties["corridor"];
			initialParameters.setSpawnCorridor(new ChanceWithMinimum(50, 10, 5+corridor)); // controls room spawn
			initialParameters.setTurnChance(new Chance(10, 5));
			initialParameters.setChildAgeModifier(3);
			initialParameters.setChildCorridorDecrement(2);
			initialParameters.setElementChance(new ElementalChance(lastPhrase.shade.element));
			var initialBuilder:Builder = new Builder(this, new Point(lastMap.width / 2, lastMap.height / 2), Direction.getRandomDirection(), initialParameters);
			builders.push(initialBuilder);
			lastMap.setTile(initialBuilder.getPosition(), Map.START);
			start = initialBuilder.getPosition();
			initialBuilder.move();
			if (beginStepping)
				while (!done)
				{
					step();
				}
			return lastMap;
		}
		
		public function step():void
		{
			if (!done)
			{
				for (var index:int = builders.length - 1; index >= 0; index--)
				{
					numberOfSteps++;
					builders[index].step();
					if (builders[index].isDone())
					{
						ends.push(builders[index].getPosition().copy());
						builders.indexOf(builders[index]);
						builders[index] = null;
						builders.splice(index, 1);
					}
				}
				if (builders.length == 0)
				{
					done = true;
					for (var indexEnd:int = ends.length - 1; indexEnd >= 0; indexEnd--)
					{
						if (lastMap.getNumberOfSurroundingTiles(ends[indexEnd]) > 1) {
							
							ends.indexOf(ends[indexEnd]);
							ends[indexEnd] = null;
							ends.splice(indexEnd, 1);
						}
					}
					if (ends.length == 0 || numberOfSteps < lastAge/2)
					{
						done = false;
						generate(true);
					}
					else
					{
						var randomEnd:int = 0;
						if (ends.length > 1)
						 randomEnd = random.nextInt(ends.length-1);
						lastMap.setTile(ends[randomEnd], Map.END);
						var widthBefore:int = width;
						var heightBefore:int = height;
						trace(lastMap);
						lastMap.trim();
						trace(lastMap);
						var widthAfter:int = lastMap.width;
						var heightAfter:int = lastMap.height;
						var widthDifference:int = widthAfter - widthBefore;
						var heightDifference:int = heightAfter - heightBefore;
						for each (var room:Room in rooms) 
						{
							room.mapPosition.add( new Point(widthDifference, heightDifference));
						}
						start.add( new Point( heightDifference, widthDifference));
					}
				}
			}
		}
		
		public function getMap() : Map {
			return lastMap;
		}
		
		public function addBuilder(child:Builder):void
		{
			builders.push(child);
		}
	
	}

}